import React, {Component, PropTypes} from 'react';

/**
 * 一个组件可以通过 getChildContext 方法返回一个对象，
 * 这个对象就是子树的 context，提供 context 的组件必须提供 childContextTypes 作为 context 的声明和验证。

 如果一个组件设置了 context，那么它的子组件都可以直接访问到里面的内容，它就像这个组件为根的子树的全局变量。
 任意深度的子组件都可以通过 contextTypes 来声明你想要的 context 里面的哪些状态，然后可以通过 this.context 访问到那些状态。

context 打破了组件和组件之间通过 props 传递数据的规范，
极大地增强了组件之间的耦合性。而且，就如全局变量一样，context 里面的数据能被随意接触就能被随意修改，
每个组件都能够改 context 里面的内容会导致程序的运行不可预料。

但是这种机制对于前端应用状态管理来说是很有帮助的，
因为毕竟很多状态都会在组件之间进行共享，context 会给我们带来很大的方便。
一些第三方的前端应用状态管理的库（例如 Redux）就是充分地利用了这种机制给我们提供便利的状态管理服务。
但我们一般不需要手动写 context，也不要用它，只需要用好这些第三方的应用状态管理库就行了。
 * 
 * 
 * 
*/

export default class Context extends Component {

    /**
     * childContextTypes，它的作用其实 propsType 验证组件 props 参数的作用类似。
     * 不过它是验证 getChildContext 返回的对象。为什么要验证 context，因为 context 是一个危险的特性，
     * 按照 React.js 团队的想法就是，把危险的事情搞复杂一些，提高使用门槛人们就不会去用了。
     * 如果你要给组件设置 context，那么 childContextTypes 是必写的
     * 
    */
    static childContextTypes = {
        themeColor: PropTypes.string.isRequired
    }

    constructor(props, context) {
        super(props, context);
        this.state = {
            themeColor: 'red'
        }
    }
    
    componentWillMount() {
        this.setState({
            themeColor: 'green'
        })
    }

    getChildContext() {
        return {
            themeColor: this.state.themeColor
        }
    } 

    render() {
        return (
             <div>
                <Header />
                <Main />
            </div>
        )
       
    }
} 

class Header extends Component {
    render() {
        return (
            <div>
                <h2>This is header</h2>
                <Title />
            </div>
        )
    }
}

class Main extends Component {
    
    render() {
        return (
            <div>
                <h2>This is main</h2>
                <Content />
            </div>
        )
    }
}

class Title extends Component {
    
    /**
     * 子组件要获取 context 里面的内容的话，就必须写 contextTypes 来声明和验证你需要获取的状态的类型，
     * 它也是必写的，如果你不写就无法获取 context 里面的状态。
    */
    static contextTypes =  {
        themeColor: PropTypes.string.isRequired
    }

    constructor(props, context) {
        super(props, context);
        console.log('this.context', this.context)
    }

    render() {
        return (
            <h1 style={{color: this.context.themeColor}}>React context title</h1>
        )
    }
    
}

function Content() {
    return (
        <h2>React context content</h2>
    )
}